#include "domain_track_interval.h"
#include <iostream>
DTInterval::DTInterval(Interval i, BoolInterval def) :
    i_(i), def_(def) {
    assertInvariant();
}

Interval DTInterval::unsafeI() const {
    //assert(def_ == alltrue);
    assertInvariant();
    return i_;
}

BoolInterval DTInterval::def() const {
    assertInvariant();
    return def_;
}

BoolInterval DTInterval::lt(const DTInterval& that) const {
    assertInvariant(); that.assertInvariant();

    if (def_ == notrue || that.def_ == notrue)
        return notrue;
    if (def_ == halftrue || that.def_ == halftrue)
        return halftrue;

    return i_.lt(that.i_);
}
BoolInterval DTInterval::eq(const DTInterval& that) const {
    assertInvariant(); that.assertInvariant();

    if (def_ == notrue || that.def_ == notrue)
        return notrue;
    if (def_ == halftrue || that.def_ == halftrue)
        return halftrue;

    return i_.eq(that.i_);
}

BoolInterval DTInterval::operator<(const DTInterval& that) const {
    assertInvariant(); that.assertInvariant();

    if (def_ == notrue || that.def_ == notrue)
        return notrue;
    if (def_ == halftrue || that.def_ == halftrue)
        return halftrue;

    return i_.lt(that.i_);
}

// sqrt todo
DTInterval DTInterval::sqrt() const {
    assertInvariant();

    // if (def_ == notrue)
    //     return *this;
    // if (def_ == halftrue)
    //     return *this;

    // sqrt运算下的量都得大于0
    if (i_.b() < 0)
        return DTInterval(i_, BoolInterval(false, false));
    else if (i_.a() >= 0)
        return DTInterval(i_.sqrt(), def_);
    else
        return DTInterval(Interval(0, i_.unsafeB()).sqrt(), BoolInterval(false, def_.b()));
}

DTInterval DTInterval::isin() const {
    Interval i = i_.isin();
    BoolInterval def = alltrue;
    if (i.a() == i_.a())
        def = halftrue;

    return DTInterval(i, def);
}

DTInterval DTInterval::icos() const {
    Interval i = i_.icos();
    BoolInterval def = alltrue;
    if (i.a() == i_.a())
        def = halftrue;

    return DTInterval(i, def);
}

DTInterval DTInterval::itan() const {
    Interval i = i_.itan();
    BoolInterval def = alltrue;
    if (i.a() == i_.a())
        def = halftrue;

    return DTInterval(i, def);
}

DTInterval DTInterval::operator^(const int& x) {
    DTInterval i(*this);
    for(int x_ = 0; x_ < x; ++x_) {
        i *= i;
    }
    return i;
}

DTInterval DTInterval::ilog() const {
    if (i_.b() < 0)
        return DTInterval(i_, BoolInterval(false, false));
    else if (i_.a() >= 0)
        return DTInterval(i_.ilog(), def_);
    else
        return DTInterval(Interval(0, i_.unsafeB()).ilog(), BoolInterval(false, def_.b()));

}

DTInterval& DTInterval::operator+=(const DTInterval& that) {
    assertInvariant(); that.assertInvariant();

    if (def_ == notrue || that.def_ == notrue) {
        def_ = notrue;
        i_ = allnan;
    }
    else if (def_ == halftrue || that.def_ == halftrue) {
        def_ = halftrue;
        i_ = allnan;
    }
    else {  // 未定义操作
        bool nanInA =
        (i_.a() == -HUGE_VAL && that.i_.a() == HUGE_VAL) ||
        (i_.a() == HUGE_VAL && that.i_.a() == -HUGE_VAL);
        bool nanInB =
        (i_.b() == -HUGE_VAL && that.i_.b() == HUGE_VAL) ||
        (i_.b() == HUGE_VAL && that.i_.b() == -HUGE_VAL);

        def_ = BoolInterval(
            (!nanInA && !nanInB),
            i_.a() != i_.b() || (!nanInA && !nanInB));

        if (def_ != alltrue)
            i_ = allnan;
        else
            i_ += that.i_;
    }

    return *this;
}
DTInterval& DTInterval::operator-=(const DTInterval& that) {
    assertInvariant(); that.assertInvariant();

    if (def_ == notrue || that.def_ == notrue) {
        def_ = notrue;
        i_ = allnan;
    }
    else if (def_ == halftrue || that.def_ == halftrue) {
        def_ = halftrue;
        i_ = allnan;
    }
    else {
        bool nanInA =
        (i_.a() == HUGE_VAL && that.i_.b() == HUGE_VAL) ||
        (i_.a() == -HUGE_VAL && that.i_.b() == -HUGE_VAL);
        bool nanInB =
        (i_.b() == HUGE_VAL && that.i_.a() == HUGE_VAL) ||
        (i_.b() == -HUGE_VAL && that.i_.a() == -HUGE_VAL);

        def_ = BoolInterval(
            (!nanInA && !nanInB),
            i_.a() != i_.b() || (!nanInA && !nanInB));

        if (def_ != alltrue)
            i_ = allnan;
        else
            i_ -= that.i_;
    }

    return *this;
}
DTInterval& DTInterval::operator*=(const DTInterval& that) {
    assertInvariant(); that.assertInvariant();

    if (def_ == notrue || that.def_ == notrue) {
        def_ = notrue;
        i_ = allnan;
    }
    else if (def_ == halftrue || that.def_ == halftrue) {
        def_ = halftrue;
        i_ = allnan;
    }
    else {  // 0×∞、0×-∞ 未定义
        bool containsZero = (i_.a() <= 0) != (i_.b() < 0);  // 判断(a,b)是否包含0

        bool thatContainsZero = (that.i_.a() <= 0) != (that.i_.b() < 0);
        //这样0x0还是允许的

        bool zeroByInf = containsZero && (abs(that.i_.a()) == HUGE_VAL || abs(that.i_.b()) == HUGE_VAL);
        bool infByZero = thatContainsZero && (abs(i_.a()) == HUGE_VAL || abs(i_.b()) == HUGE_VAL);

        def_ = BoolInterval(
            (!zeroByInf && !infByZero),
            (i_.a() != i_.b()) || (that.i_.a() != that.i_.b()) || (!zeroByInf && !infByZero));


        if (def_ != alltrue)
            i_ = allnan;
        else
            i_ *= that.i_;
    }

    return *this;
}
DTInterval& DTInterval::operator/=(const DTInterval& that) {
    assertInvariant(); that.assertInvariant();

    if (def_ == notrue || that.def_ == notrue) {
        def_ = notrue;
        i_ = allnan;
    }
    else if (def_ == halftrue || that.def_ == halftrue) {
        def_ = halftrue;
        i_ = allnan;
    }
    else {
        bool thatContainsZero = (that.i_.a() <= 0) != (that.i_.b() < 0);

        bool infByInf =
        (abs(i_.a()) == HUGE_VAL || abs(i_.b()) == HUGE_VAL) &&
        (abs(that.i_.a()) == HUGE_VAL || abs(that.i_.b()) == HUGE_VAL);

        bool divByZero = thatContainsZero;

        def_ = BoolInterval(
            (!infByInf && !divByZero),
            i_.a() != i_.b() || that.i_.a() != that.i_.b() || (!infByInf && !divByZero));

        if (def_ != alltrue)
            i_ = allnan;
        else
            i_ /= that.i_;
    }

    return *this;
}

void swap(DTInterval& a, DTInterval& b) {
    a.assertInvariant(); b.assertInvariant();

    using std::swap;
    swap(a.i_, b.i_);
    swap(a.def_, b.def_);
}

void DTInterval::assertInvariant() const {
    // assert(
    //     def_ == alltrue || (std::isnan(i_.a()) && std::isnan(i_.b()))  // (T, F)终止（a, b） a是无穷，b有定义
    // );
}

